package com.xlq.consultant.config;

import com.xlq.consultant.repository.RedisChatMemoryStore;
import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class CommonConfig {
    @Resource
    private OpenAiChatModel openAiChatModel;

    @Resource
    private RedisChatMemoryStore redisChatMemoryStore;

    @Resource
    private EmbeddingModel embeddingModel;

    @Resource
    private RedisEmbeddingStore redisEmbeddingStore;
    //
//    @Bean
//    public ConsultantService consultantService(){
//         ConsultantService cs = AiServices.builder(ConsultantService.class)
//                .chatModel(openAiChatModel)
//                .build();
//        return cs;
//    }
    @Bean
    public ChatMemory chatMemory() {
        return new MessageWindowChatMemory.Builder().maxMessages(20)// 设置会话最大消息数20
                .build();
    }

    @Bean
    public ChatMemoryProvider chatMemoryProvider() {
        // 如果ioc容器没有对应id的会话记忆对象，就调用这个提供者创建一个
        ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {
            @Override
            public ChatMemory get(Object memoryId) {
                return MessageWindowChatMemory.builder().maxMessages(20)//最大会话记录数量
                        .chatMemoryStore(redisChatMemoryStore)//配置ChatMemoryStore
                        .id(memoryId)//id值
                        .build();
            }
        };
        return chatMemoryProvider;
    }

    /**
     * 配置向量数据库
     *
     * @return
     */
//    @Bean
    public EmbeddingStore store() {
        //1.加载文档进内存
//        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content",new ApachePdfBoxDocumentParser());//加载文档的时候指定解析器
//        List<Document> documents = FileSystemDocumentLoader.loadDocuments("C:\\Users\\Administrator\\ideaProjects\\consultant\\src\\main\\resources\\content");

        // 2.构建向量数据库操作对象  操作的是内存版本的向量数据库
//        InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
        //构建文档分割器对象
        DocumentSplitter splitter = DocumentSplitters.recursive(500, 100);

        //3.构建一个EmbeddingStoreIngestor对象,完成文本数据切割,向量化, 存储
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .embeddingStore(redisEmbeddingStore)//设置外部向量数据库操作对象
                .documentSplitter(splitter)
                .embeddingModel(embeddingModel)
                .build();

        ingestor.ingest(documents);
        return redisEmbeddingStore;
    }


    /**
     * 配置向量数据库检索对象
     */
    @Bean
    public ContentRetriever embeddingStoreContentRetriever(RedisEmbeddingStore redisEmbeddingStore) {
        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(redisEmbeddingStore)//设置外部向量数据库操作对象
                .embeddingModel(embeddingModel)
                .minScore(0.6)//设置最小分数
                .maxResults(3)//设置最大片段数量
                .build();
    }

}
